package xfuzzy.xfghl.replacement;

import java.util.Random;

import xfuzzy.xfghl.codification.DoubleChromosome;
import xfuzzy.xfghl.population.Population;

/**
 * Clase que realiza el reemplazo en la poblacion usando Crowding generalizado
 * @author Alberto David Fernandez Fernandez
 * */

public class GeneralizedCrowdingReplacement extends Replacement {
	
	/**
	 * Factor de escala para la probabilidad de reemplazo
	 * */
	private double scalingFactor;
	
	/**
	 * Variable para la generacion de numeros aleatorios
	 * */
	private Random rnd;
	
	/**
	 * Constructor de la clase
	 * @param scalingFactor Factor de escala del reemplazo
	 * @param seed Semilla del generador de numeros aleatorios
	 * */
	
	public GeneralizedCrowdingReplacement(double scalingFactor, long seed)  {
		
		this.scalingFactor = scalingFactor;
		this.rnd = new Random(seed);
	}
	
	/**
	 * Metodo que selecciona un individuo para el reemplazo
	 * @param child Individuo a comparar
	 * @param father Individuo a comparar
	 * @return DoubleChromosome Individuo seleccionado 
	 * */
	
	public DoubleChromosome generalizedCrowding(DoubleChromosome child, DoubleChromosome father)  {
		
		double randomValue = rnd.nextDouble(), probReplacement = 0.0;
		if (child.getFitness() < father.getFitness())  {
			probReplacement = child.getFitness() / (child.getFitness() + scalingFactor * father.getFitness());
		}
		else  {
			if (child.getFitness() > father.getFitness())  {
				probReplacement = (scalingFactor * child.getFitness()) / (scalingFactor * father.getFitness() + father.getFitness()); 
			}
			else  {
				probReplacement = 0.5;
			}
		}
		if (probReplacement > randomValue)
			return child;
		else
			return father;
	}
	
	/**
	 * Metodo que reemplaza los individuos en la poblacion
	 * @param population Poblacion de individuos
	 * @param child1 Nuevo individuo de reemplazo
	 * @param child2 Nuevo individuo de reemplazo
	 * @param father1 Individuo a reemplazar
	 * @param father2 Individuo a reemplazar
	 * */
	
	public void replace(Population population, DoubleChromosome child1, DoubleChromosome child2, DoubleChromosome father1, DoubleChromosome father2)  {
		
		DoubleChromosome winner1 = null, winner2 = null;
		if (this.rnd.nextDouble() > 0.5)  {
			winner1 = this.generalizedCrowding(child1, father1);
			winner2 = this.generalizedCrowding(child2, father2);
		}
		else  {
			winner1 = this.generalizedCrowding(child2, father1);
			winner2 = this.generalizedCrowding(child1, father2);
		}
		DoubleChromosome aux = null;
		for (int index = 0; index < population.getPoblacionSize(); index++)  {
			 aux = population.getIndividuo(index);
			 if (aux.getIdentification().compareTo(father1.getIdentification()) == 0)  {
				 population.setIndividuo(index, winner1);
			 }
			 if (aux.getIdentification().compareTo(father2.getIdentification()) == 0)  {
				 population.setIndividuo(index, winner2);
			 }
		}
	}
}
